home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 October / CHIP Turkiye Ekim 2000.iso / prog / naps / 04 / setup.exe / Gnucleus / GnuTransfer.cpp < prev    next >
C/C++ Source or Header  |  2000-07-15  |  14KB  |  595 lines

  1. /********************************************************************************
  2.  
  3.     Gnucleus - A node application for the Gnutella network
  4.     Copyright (C) 2000 John Marshall
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     For support, questions, comments, etc...
  20.     E-Mail: 
  21.         swabby@c0re.net
  22.     
  23.     Address:
  24.         21 Cadogan Way
  25.         Nashua, NH, USA 03062
  26.  
  27. ********************************************************************************/
  28.  
  29. // GnuTransfer.cpp : implementation file
  30. //
  31. #include "stdafx.h"
  32. #include "Gnucleus.h"
  33. #include "GnucleusDoc.h"
  34.  
  35. #include "ViewSearch.h"
  36. #include "ViewTransfer.h"
  37.  
  38. #include "GnuHash.h"
  39. #include "GnuControl.h"
  40. #include "GnuTransfer.h"
  41.  
  42. #include <process.h>
  43.  
  44. #ifdef _DEBUG
  45. #define new DEBUG_NEW
  46. #undef THIS_FILE
  47. static char THIS_FILE[] = __FILE__;
  48. #endif
  49.  
  50. IMPLEMENT_DYNCREATE(CGnuTransfer, CAsyncSocket)
  51.  
  52. /////////////////////////////////////////////////////////////////////////////
  53. // CGnuTransfer
  54.  
  55. CGnuTransfer::CGnuTransfer()
  56. {
  57.     Initialize();
  58.     IsFileOpen = 0;
  59. }
  60.  
  61. CGnuTransfer::CGnuTransfer(CGnuControl *pComm)
  62. {
  63.     Initialize();
  64.     GnuComm = pComm;
  65. }
  66.  
  67. CGnuTransfer::Initialize()
  68. {
  69.     GnuComm = NULL;
  70.     next = NULL;
  71.     
  72.     IsFileOpen = 0;
  73.     IsTransfering = 0;
  74.     
  75.     BytesCompleted = 0;
  76.     OldBytesCompleted = 0;
  77.     OldRate = 0;
  78.  
  79.     m_dwBytesIn = m_dwBytesOut = m_dwTotalBytesIn = m_dwTotalBytesOut
  80.         = m_dwByteAllottmentOut = m_dwByteAllottmentIn = 0;
  81.  
  82.     
  83.     AllocBw = -1;
  84.  
  85.     m_threadHandle = NULL;
  86.     m_timeLastHeardAT = CTime::GetCurrentTime();
  87. }
  88.  
  89. CGnuTransfer::~CGnuTransfer()
  90. {    
  91.     IsTransfering = 0;
  92.  
  93.     if(m_threadHandle)
  94.     {
  95.         switch (::WaitForSingleObject (m_threadHandle, 10000))
  96.         {
  97.         case WAIT_OBJECT_0:    // Normal, the thread exited properly
  98.             break;
  99.         case WAIT_TIMEOUT:    // Thread didn't exit, kill it
  100.             ::TerminateThread (m_threadHandle, 0);
  101.             break;
  102.         case WAIT_FAILED:    // Thread probably exited before we got to the waitforsingleobject
  103.             break;
  104.         default:            // err
  105.             ::TerminateThread (m_threadHandle, 0);
  106.             break;
  107.         }
  108.     }
  109. }
  110.  
  111.  
  112. // Do not edit the following lines, which are needed by ClassWizard.
  113. #if 0
  114. BEGIN_MESSAGE_MAP(CGnuTransfer, CAsyncSocket)
  115.     //{{AFX_MSG_MAP(CGnuTransfer)
  116.     //}}AFX_MSG_MAP
  117. END_MESSAGE_MAP()
  118. #endif    // 0
  119.  
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CGnuTransfer member functions
  122.  
  123. void CGnuTransfer::OnConnect(int nErrorCode) 
  124. {
  125.     if(nErrorCode == 0)
  126.     {
  127.         if(Type == 'D')
  128.         {
  129.             Status = "Remotely queued";
  130.  
  131.             CString GetCommand = "GET /get/";
  132.                     GetCommand += DWrdtoStr(FileInfo.Index);
  133.                     GetCommand += "/";
  134.                     GetCommand += FileInfo.FileName;
  135.                     GetCommand += " HTTP/1.0\r\nConnection: Keep-Alive\r\nRange: bytes=";
  136.                     GetCommand += DWrdtoStr(BytesCompleted);
  137.                     GetCommand += "-\r\n\r\n";
  138.  
  139.             Send(GetCommand, GetCommand.GetLength());
  140.  
  141.             GnuComm->BytesOut += GetCommand.GetLength ();
  142.         }
  143.  
  144.         // Incoming push
  145.         if(Type == 'U')
  146.         {
  147.             byte *ClientID = (byte *) &FileInfo.Guid;
  148.             
  149.             std::basic_string<char> GiveMsg("GIV ");
  150.             GiveMsg += DWrdtoStr(FileInfo.Index) + ": ";
  151.  
  152.             TCHAR buff[33];
  153.             sprintf(buff, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
  154.                     ClientID[0],  ClientID[1],  ClientID[2],  ClientID[3],  ClientID[4],
  155.                     ClientID[5],  ClientID[6],  ClientID[7],  ClientID[8],  ClientID[9],
  156.                     ClientID[10], ClientID[11], ClientID[12], ClientID[13], ClientID[14],
  157.                     ClientID[15]);
  158.  
  159.             GiveMsg.append(buff);
  160.             
  161.             std::vector<SharedFile>::iterator it;
  162.  
  163.             int loop;
  164.             for(loop = 0, it = GnuComm->Doc->SharedFiles.begin(); 
  165.                 it != GnuComm->Doc->SharedFiles.end();
  166.                 loop++, it++)
  167.             {
  168.                 if(loop == FileInfo.Index)
  169.                     FileInfo.FileName = (*it).FileName;
  170.             }
  171.             
  172.             if(FileInfo.FileName == "")
  173.                 return;
  174.  
  175.             GiveMsg += "/" + FileInfo.FileName + "\n\n";
  176.  
  177.             Send(GiveMsg.c_str(), GiveMsg.length());
  178.         }
  179.     }
  180.     else
  181.         Status = "Connection Refused";
  182.  
  183.     
  184.     CAsyncSocket::OnConnect(nErrorCode);
  185. }
  186.  
  187. void CGnuTransfer::OnReceive(int nErrorCode) 
  188. {
  189.     DWORD dwSize = 0;
  190.     int iReceiveLength = 0;
  191.     int length = 0;
  192.     
  193.     if (!IOCtl (FIONREAD, &dwSize))
  194.     {
  195.         // If we can't tell how many bytes are waiting on the socket, something's gone wrong.
  196.         Status = "Bad Socket";
  197.         Close ();
  198.  
  199.         return;
  200.     }
  201.  
  202.     byte *pBuff = new byte[dwSize+1];
  203.  
  204.     iReceiveLength = Receive(pBuff, dwSize);
  205.  
  206.     switch (iReceiveLength)
  207.     {
  208.     case 0:
  209.         // Connection has been closed, shutdown
  210.  
  211.         WantToDisconnect();
  212. //        m_CanRelease = true;
  213. //        CleanUp();
  214.         break;
  215.  
  216.     case SOCKET_ERROR:
  217.         OutputDebugString("CGnuSock::OnReceive - SOCKET_ERROR\n");
  218.  
  219.         // received an error, see what it is and handle.
  220.         switch(GetLastError())
  221.         {
  222.             // fatal errors, need to disconnect
  223.         default:
  224.         case WSAECONNRESET:        // The virtual circuit was reset by the remote side.
  225.         case WSAENOTCONN:        // The socket is not connected.
  226.         case WSAENOTSOCK:        // The descriptor is not a socket.
  227.         case WSAESHUTDOWN:        // The socket has been shut down
  228.         case WSAECONNABORTED:    // The virtual circuit was aborted due to timeout or other failure.
  229.         case WSAEWOULDBLOCK:    //The socket is marked as nonblocking and the Receive operation would block.  Shouldn't happen.
  230.         case WSAENETDOWN:        // detected that the network subsystem failed
  231.  
  232.             WantToDisconnect();
  233. //            m_CanRelease = true;
  234. //            CleanUp();
  235.  
  236.             break;
  237.  
  238.             // non fatal errors, just handle individualy
  239.         case WSAEMSGSIZE:        // The datagram was too large to fit into the specified buffer and was truncated.
  240.                                 // Shouldn't happen because buffer is veriable sized
  241.             WantToDisconnect();
  242. //            m_CanRelease = true;
  243. //            CleanUp();
  244.  
  245.             break;
  246.         }
  247.         delete [] pBuff;
  248.         return;
  249.         break;
  250.     default:        // just normal data
  251.         m_timeLastHeardAT = CTime::GetCurrentTime();
  252.         length += iReceiveLength;
  253.     }
  254.  
  255.  
  256.     m_dwBytesIn += length;
  257.     GnuComm->BytesIn += length;
  258.  
  259.     pBuff[length] = 0;
  260.  
  261.     CString FileHeader = (char *) pBuff;
  262.  
  263.     // If this is an upload, get out of here
  264.     if(FileHeader.Find( "GET /get/") != -1)
  265.         ((CViewTransfer *) ((CGnucleusApp *) AfxGetApp())->TransferFrame->GetActiveView())->NewUpload(FileHeader, NULL);
  266.  
  267.     else if(IsTransfering == 0)
  268.     {
  269.         // Be ready for response in the format of "HTTP/1.1 <Response-code>".
  270.         // Anything that doesn't start with HTTP should still be dropped
  271.         if(FileHeader.Find("HTTP 200 OK\r\nServer: ") != -1)
  272.         {
  273.             FileHeader.MakeLower();
  274.  
  275.             // Extract client sending and file size from the header
  276.             int front  = FileHeader.Find("server: ") + 8;
  277.             int back   = FileHeader.Find("\r\n", front);
  278.             ClientName = FileHeader.Mid(front, back - front);
  279.  
  280.             if(BytesCompleted)
  281.             {
  282.                 front = FileHeader.Find("bytes=", back) + 6;
  283.                 front = FileHeader.Find("-", front) + 1;
  284.                 back  = FileHeader.Find("/", front);
  285.             }
  286.             else
  287.             {
  288.                 front = FileHeader.Find("content-length:") + 15;
  289.                 back  = FileHeader.Find("\r\n\r\n", front);
  290.  
  291.                 FileSize = atol( FileHeader.Mid(front, back - front));
  292.             }
  293.  
  294.             IsTransfering = 1;
  295.             Status = "Downloading";
  296.                 
  297.             // Create the file and start initial d/l
  298.             if(BytesCompleted)
  299.             {
  300.                 if(File.Open(GnuComm->Doc->m_DownloadDir + "\\" + (FileInfo.LocalFileName.IsEmpty() ? FileInfo.FileName : FileInfo.LocalFileName), CFile::modeCreate | CFile::modeNoTruncate | CFile::modeWrite | CFile::shareDenyNone))
  301.                     IsFileOpen = 1;
  302.  
  303.                 File.SeekToEnd();
  304.             }
  305.             else
  306.             {
  307.                 if (FileInfo.Size == 0)
  308.                 {
  309.                     FileInfo.Size = FileSize;
  310.                 }
  311.                 if(FileSize != FileInfo.Size)
  312.                 {
  313.                     Close();
  314.                     Status = "File Invalid";
  315.  
  316.                     delete [] pBuff;
  317.                     return;
  318.                 }
  319.             
  320.                 if(File.Open(GnuComm->Doc->m_DownloadDir + "\\" + (FileInfo.LocalFileName.IsEmpty() ? FileInfo.FileName : FileInfo.LocalFileName), CFile::modeCreate | CFile::modeWrite | CFile::shareDenyNone))
  321.                     IsFileOpen = 1;
  322.             }
  323.             
  324.             int begin  = FileHeader.Find("\r\n\r\n", front) + 4;
  325.             File.Write(&pBuff[begin], length - begin);
  326.             BytesCompleted += length - begin;
  327.         }
  328.         else
  329.         {
  330.             int httpError = 0;
  331.  
  332.             ::sscanf (FileHeader, "HTTP %d %*s", &httpError);
  333.  
  334.             if (httpError != 0)
  335.             {
  336.                 CString err;
  337.  
  338.                 Status.Format ("HTTP %d Error", httpError);
  339.             }
  340.             else
  341.             {
  342.                 Status = "Bad Header";
  343.             }
  344.             Close();
  345.         }
  346.     }
  347.     else
  348.     {
  349.         if(BytesCompleted < FileSize)
  350.         {
  351.             File.Write(pBuff, length);
  352.             BytesCompleted += length;
  353.         }
  354.         else
  355.         {
  356.             IsTransfering = 0;
  357.             Close();
  358.  
  359.             if(IsFileOpen)
  360.                 File.Close();
  361.  
  362.             IsFileOpen = false;
  363.         }
  364.  
  365.         if(BytesCompleted == FileSize)
  366.             Status = "Completed";
  367.     }
  368.  
  369.     m_timeLastHeardAT = CTime::GetCurrentTime();
  370.  
  371.     delete [] pBuff;
  372.     
  373.     CAsyncSocket::OnReceive(nErrorCode);
  374. }
  375.  
  376. void CGnuTransfer::OnClose(int nErrorCode) 
  377. {
  378.     IsTransfering = 0;
  379.  
  380.     if(IsFileOpen)
  381.         File.Close();
  382.     IsFileOpen = false;
  383.  
  384.     // clean out the buffer
  385.     char * pBuf = new char[101];
  386.     int iRet = 0;
  387.     while( (iRet = Receive(pBuf, 100)) != 0 && iRet != SOCKET_ERROR );
  388.     delete [] pBuf;
  389.  
  390.     if(BytesCompleted == FileSize)
  391.         Status = "Completed";
  392.     else
  393.         Status = "Remotely Canceled";
  394.  
  395.     CAsyncSocket::OnClose(nErrorCode);
  396. }
  397.  
  398. void CGnuTransfer::Pause()
  399. {
  400.     IsTransfering = 0;
  401.     WantToDisconnect();
  402.     Close();
  403.     
  404.     if(IsFileOpen)
  405.         File.Close();
  406.     IsFileOpen = false;
  407.  
  408.     Status = "Paused";
  409. }
  410.  
  411. void CGnuTransfer::Resume()
  412. {
  413.     Status = "Active";
  414. }
  415.  
  416. void CGnuTransfer::StartSending()
  417. {
  418.     // Send the header
  419.     std::basic_string<char> Header("HTTP 200 OK\r\nServer: Gnutella\r\nContent-type:application/binary\r\n");
  420.  
  421.     if(BytesCompleted)
  422.         Header += "Content-length: bytes=" + DWrdtoStr(BytesCompleted) + "-" + DWrdtoStr(FileSize - 1) + "/" + DWrdtoStr(FileSize) + "-\r\n\r\n"; 
  423.     else
  424.         Header += "Content-length:" + DWrdtoStr(FileSize) + "\r\n\r\n";
  425.  
  426.     // Send the header
  427.     if(Header.length() != Send( Header.c_str(), Header.length()))
  428.         Close();
  429.     
  430.     if( !File.Open(FileInfo.FileName, CFile::modeRead | CFile::shareDenyNone) )
  431.         return;
  432.  
  433.     IsTransfering = 1;
  434.     IsFileOpen = 1;
  435.     Status = "Uploading";
  436.  
  437.     File.Seek(BytesCompleted, CFile::begin);
  438.  
  439.     m_threadHandle = (HANDLE) ::_beginthread (SendFile, 0, this);
  440. }
  441.  
  442. void CGnuTransfer::WantToDisconnect()
  443. {
  444.     // Let spock know that he is going to die, so it might as well
  445.     // speed up the process.
  446.  
  447.     if(m_hSocket != INVALID_SOCKET)
  448.     {
  449.         AsyncSelect(FD_CLOSE);
  450.         ShutDown(sends);
  451.     }
  452.  
  453.     IsTransfering = false;
  454. }
  455.  
  456. void CGnuTransfer::SendFile(void *Link)
  457. {
  458.     CGnuTransfer *GnuTrans = (CGnuTransfer *) Link;
  459.     CGnucleusDoc *Doc = GnuTrans->GnuComm->Doc;
  460.  
  461.  
  462.     int AllocBytes = 32000;
  463.  
  464. /*
  465.     if(Doc->m_LimitUp)
  466.         GnuTrans->AllocBw = Doc->m_LimitUp * 1024 / (1 + Doc->ActiveUploads);
  467.     else
  468.         GnuTrans->AllocBw = -1;
  469.     
  470.     // Bandwidth management for uploads
  471.     if(GnuTrans->AllocBw != -1)
  472.     {
  473.         if(GnuTrans->AllocBw > 32000)
  474.             GnuTrans->AllocBw -= 32000;
  475.         else
  476.         {
  477.             AllocBytes = GnuTrans->AllocBw;
  478.             GnuTrans->AllocBw = 0;
  479.         }
  480.     }
  481. */
  482.  
  483.     if(Doc->m_LimitUp)
  484.         GnuTrans->m_dwByteAllottmentOut = Doc->m_LimitUp * 1024 / 2;    // preliminary allotment
  485.     else if(Doc->m_LimitTotal)
  486.         GnuTrans->m_dwByteAllottmentOut = Doc->m_LimitTotal * 1024 / 3;// preliminary allotment
  487.     
  488.     if(GnuTrans->m_dwByteAllottmentOut)
  489.     {
  490.         if(GnuTrans->m_dwByteAllottmentOut - GnuTrans->m_dwBytesOut < 32000)    // if there isn't 32k available, take what is.
  491.         {
  492.             AllocBytes = GnuTrans->m_dwByteAllottmentOut - GnuTrans->m_dwBytesOut;
  493.         }
  494.     }
  495.  
  496.  
  497.     BYTE *buffer = new BYTE[AllocBytes];
  498.  
  499.     int bytesRead = 0;
  500.     if(GnuTrans->IsFileOpen)
  501.         bytesRead = GnuTrans->File.Read(buffer, AllocBytes);
  502.     
  503.     while(GnuTrans->IsTransfering && 
  504.           GnuTrans->BytesCompleted != GnuTrans->FileSize && 
  505.           bytesRead > 0)
  506.     {
  507.         int bytesSent = 0;
  508.  
  509.         if(GnuTrans->IsTransfering)
  510.         {
  511.             bytesSent = GnuTrans->Send(buffer + bytesSent, bytesRead - bytesSent);
  512.             GnuTrans->GnuComm->BytesOut += bytesSent;
  513.             GnuTrans->m_dwBytesOut += bytesSent;
  514.         }
  515.         while(GnuTrans->IsTransfering && bytesSent < bytesRead)
  516.         {
  517.             if(GetLastError() == WSAEWOULDBLOCK)
  518.                 bytesSent += 1;
  519.             else if(GetLastError())
  520.             {
  521.                 if(GnuTrans->IsTransfering)
  522.                     GnuTrans->Status = "Error sending";
  523.  
  524.                 delete [] buffer;
  525.                 return;
  526.             }
  527.             
  528.             if(GnuTrans->IsTransfering)
  529.             {
  530.                 bytesSent += GnuTrans->Send(buffer + bytesSent, bytesRead - bytesSent);
  531.                 GnuTrans->GnuComm->BytesOut += bytesSent;
  532.                 GnuTrans->m_dwBytesOut += bytesSent;
  533.             }
  534.         }
  535.         
  536.         if(GnuTrans->IsTransfering)
  537.         {
  538.             GnuTrans->BytesCompleted += bytesSent;
  539.             GnuTrans->m_dwTotalBytesOut += bytesSent;
  540.  
  541.             if(GnuTrans->BytesCompleted == GnuTrans->FileSize)
  542.             {
  543.                 GnuTrans->Status = "Completed";
  544.                 GnuTrans->IsTransfering = 0;
  545.             }
  546.             else
  547.             {
  548.                 delete [] buffer;
  549.  
  550.                 AllocBytes = 32000;
  551.  
  552.                 // Bandwidth management for uploads
  553. /*
  554.                 if(GnuTrans->AllocBw != -1)
  555.                 {
  556.                     while(GnuTrans->IsTransfering && !GnuTrans->AllocBw);
  557.  
  558.                     if(GnuTrans->AllocBw > 32000)
  559.                         GnuTrans->AllocBw -= 32000;
  560.                     else
  561.                     {
  562.                         AllocBytes = GnuTrans->AllocBw;
  563.                         GnuTrans->AllocBw = 0;
  564.                     }
  565.                 }
  566. */
  567.                 if(GnuTrans->m_dwByteAllottmentOut)
  568.                 {
  569.                     while (GnuTrans->IsTransfering 
  570.                         && (GnuTrans->m_dwBytesOut >= GnuTrans->m_dwByteAllottmentOut)
  571.                         && GnuTrans->m_dwByteAllottmentOut)
  572.                         Sleep(50);        // wait half a second
  573.  
  574.                     if(GnuTrans->m_dwByteAllottmentOut - GnuTrans->m_dwBytesOut < 32000)    // if there isn't 32k available, take what is.
  575.                     {
  576.                         AllocBytes = GnuTrans->m_dwByteAllottmentOut - GnuTrans->m_dwBytesOut;
  577.                     }
  578.                 }
  579.  
  580.                 if(!AllocBytes)
  581.                     AllocBytes = 32000;
  582.                     
  583.                 buffer = new BYTE[AllocBytes];
  584.  
  585.                 if(GnuTrans->IsFileOpen)
  586.                     bytesRead = GnuTrans->File.Read(buffer, AllocBytes);
  587.             }
  588.         }
  589.     }
  590.     
  591.     delete [] buffer;
  592. }
  593.  
  594.  
  595.